﻿#region License

// PentaBiz - Sustainable Software Development Framework Copyright (C) 2013 Zoltán Csizmazia
// 
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;

namespace PentaBiz.IoC
{
    public class MefContainer : Disposable
    {
        private static readonly MefContainer _default = new MefContainer();
        private readonly AggregateCatalog _aggregateCatalog;
        private readonly CompositionContainer _compositionContainer;
        private readonly DirectoryCatalog _directoryCatalog;

        /// <summary>
        ///     Initializes a new instance of the <see cref="MefContainer" /> class.
        /// </summary>
        public MefContainer()
            : this(new DirectoryInfo(".\\"))
        {
        }


        /// <summary>
        ///     Initializes a new instance of the <see cref="MefContainer" /> class.
        /// </summary>
        /// <param name="directory">The directory.</param>
        /// <param name="searchPattern">The search pattern.</param>
        public MefContainer(DirectoryInfo directory, string searchPattern = "PentaBiz.*.dll")
        {
            _directoryCatalog = new DirectoryCatalog(directory.FullName, searchPattern);
            _aggregateCatalog = new AggregateCatalog(_directoryCatalog);
            _compositionContainer = new CompositionContainer(_aggregateCatalog);
        }

        /// <summary>
        ///     Gets the default container.
        /// </summary>
        /// <value>
        ///     The default container.
        /// </value>
        public static MefContainer Default
        {
            get { return _default; }
        }

        protected override void OnDisposing()
        {
            _directoryCatalog.Dispose();
            _aggregateCatalog.Dispose();
            _compositionContainer.Dispose();
            base.OnDisposing();
        }

        /// <summary>
        ///     Registers the assembly.
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        public void RegisterAssembly(Assembly assembly)
        {
            EnsureInstanceNotDisposed();
            _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(assembly));
        }

        /// <summary>
        ///     Unregisters the assembly.
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        public void UnregisterAssembly(Assembly assembly)
        {
            EnsureInstanceNotDisposed();
            AssemblyCatalog c =
                _aggregateCatalog.Catalogs.OfType<AssemblyCatalog>().FirstOrDefault(a => a.Assembly == assembly);
            _aggregateCatalog.Catalogs.Remove(c);
        }

        public Lazy<T> GetExport<T>()
        {
            EnsureInstanceNotDisposed();
            return _compositionContainer.GetExport<T>();
        }

        public Lazy<T, TMetadata> GetExport<T, TMetadata>()
        {
            EnsureInstanceNotDisposed();
            return _compositionContainer.GetExport<T, TMetadata>();
        }


        public IEnumerable<Lazy<T>> GetExports<T>()
        {
            EnsureInstanceNotDisposed();
            return _compositionContainer.GetExports<T>();
        }

        public IEnumerable<Lazy<T, TMetadata>> GetExports<T, TMetadata>()
        {
            EnsureInstanceNotDisposed();
            return _compositionContainer.GetExports<T, TMetadata>();
        }
    }
}